#include <rclcpp/rclcpp.hpp>
#include <rclcpp_action/rclcpp_action.hpp>
#include "example_interfaces/action/fibonacci.hpp"

class FibonacciActionClient : public rclcpp::Node
{
public:
    using Fibonacci = example_interfaces::action::Fibonacci;

    FibonacciActionClient() : Node("fibonacci_action_client")
    {
        client_ = rclcpp_action::create_client<Fibonacci>(this, "fibonacci");

        if (!client_->wait_for_action_server(std::chrono::seconds(5)))
        {
            RCLCPP_ERROR(this->get_logger(), "Action server not available");
            return;
        }

        auto goal_msg = Fibonacci::Goal();
        goal_msg.order = 10; // 请求生成前10项斐波那契数列

        auto send_goal_options = rclcpp_action::Client<Fibonacci>::SendGoalOptions();
        send_goal_options.goal_response_callback = std::bind(&FibonacciActionClient::goal_response_callback, this, std::placeholders::_1);
        send_goal_options.feedback_callback = std::bind(&FibonacciActionClient::feedback_callback, this, std::placeholders::_1, std::placeholders::_2);
        send_goal_options.result_callback = std::bind(&FibonacciActionClient::result_callback, this, std::placeholders::_1);

        client_->async_send_goal(goal_msg, send_goal_options);
    }

private:
    // Goal response callback
    void goal_response_callback(const rclcpp_action::ClientGoalHandle<Fibonacci>::SharedPtr goal_handle)
    {
        if (!goal_handle)
        {
            RCLCPP_INFO(this->get_logger(), "Goal was rejected");
        }
        else
        {
            RCLCPP_INFO(this->get_logger(), "Goal accepted");
        }
    }

    // Feedback callback
    void feedback_callback(rclcpp_action::ClientGoalHandle<Fibonacci>::SharedPtr,const std::shared_ptr<const Fibonacci::Feedback> feedback)
    {
        RCLCPP_INFO(this->get_logger(), "Received feedback: %d", feedback->sequence.back());
    }

    // Result callback
    void result_callback(const rclcpp_action::ClientGoalHandle<Fibonacci>::WrappedResult &result)
    {
        if (result.code == rclcpp_action::ResultCode::SUCCEEDED)
        {
            RCLCPP_INFO(this->get_logger(), "Result received:");
            for (const auto &value : result.result->sequence)
            {
                RCLCPP_INFO(this->get_logger(), "%d", value);
            }
        }
        else
        {
            RCLCPP_INFO(this->get_logger(), "Goal failed or was canceled");
        }
    }

    rclcpp_action::Client<Fibonacci>::SharedPtr client_;
};

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    auto node = std::make_shared<FibonacciActionClient>();
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}
